<template>
  <div class="three">
    <div ref="container"></div>
  </div>
  <div style="padding: 30px">
    <el-button size="mini" @click="addAxes">添加坐标系</el-button>

    <el-button size="mini" @click="delAxes">移除坐标系</el-button>
  </div>
</template>

<script setup lang="ts">
// 下面引入便于一步一步教程，自己写全放一个就行了
import {
  WebGLRenderer, //渲染器
  Scene, //场景
  PerspectiveCamera, //相机
  Color,
  PlaneGeometry,
  TextureLoader,
  Clock,
  PointLight,
  Vector3,
  LineCurve3,
  QuadraticBezierCurve3,
  CurvePath,
  TubeGeometry,
  Points,
  PointsMaterial,
  BufferGeometry,
  BufferAttribute,
  LineBasicMaterial,
  CatmullRomCurve3,
  RepeatWrapping,
  MeshLambertMaterial, // 颜色转换
} from "three";
import * as THREE from "three";
import astar from "javascript-astar";

import {
  AxesHelper, // 辅助坐标
} from "three";
import {
  Mesh,
  IcosahedronGeometry,
  SpotLight,
  DoubleSide,
  MeshBasicMaterial,
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import type { Deps } from "@/ThreeClass/publicDeps";
import { RenGLTFLoader } from "@/ThreeClass/RenGLTFLoader";
import { RenGLTFLoaderJiqi } from "@/ThreeClass/RenGLTFLoaderJiqi";
import { ref, onMounted, onUnmounted } from "vue";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { pineaInit } from "@/ThreeClass/initPinea";
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
const tietu =
  "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4415327a-1d82-4985-8302-44b07a8498c0%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1687512010&t=df81831ff29236e2796899fdcaf43b74";
const container = ref<HTMLElement | null>(null); // 插入的dom元素
const scene: Scene = new Scene(); // 场景
const camera = new PerspectiveCamera(60, window.innerWidth / 600, 1, 10000); // 镜头
camera.position.set(0, 5, 300);
const renderer = new WebGLRenderer(); // 渲染器
const deps = ref<Deps>();
const controls = ref();
const clock = new Clock();
const gltfLoader = new GLTFLoader();
const textureLoader = new TextureLoader();
const ws = 10;
const length = 300;
const start = (length / 2) * -1;
const end = length / 2;

// const light = new PointLight(0xffffff, 1000, 1000, 1000);
// light.position.set(1000, 1000, 1000);
// scene.add(light);
// const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// // 平行光设置产生阴影的光源对象,开启光源阴影的计算功能
// directionalLight.castShadow = true;
// scene.add(directionalLight);
onMounted(() => {
  initThree();
  camera.position.set(0, length * 1.2, 0); //x轴方向观察
  camera.lookAt(0, 0, 0); //重新计算相机视线方向
  renderer.render(scene, camera); // 重新渲染
  window.addEventListener("click", onClick, false);
});

onUnmounted(() => {
  window.removeEventListener("click", onClick, false);
});

const addAxes = () => {
  const axisHelper = new AxesHelper(2000);
  axisHelper.name = "axis";
  scene.add(axisHelper); // 把创建的坐标体系加入天地！
  renderer.render(scene, camera); // 重新渲染
};
const delAxes = () => {
  var selectedObject = scene.getObjectByName("axis");
  selectedObject.geometry.dispose();
  selectedObject.material.dispose();
  scene.remove(selectedObject);
  renderer.render(scene, camera); // 重新渲染
};

const width = window.innerWidth;
const height = 600;
const initThree = () => {
  // 设置场景颜色
  scene.background = new Color("#ffffff"); // 设置背景色
  renderer.setSize(width, height);
  (container.value as HTMLElement).appendChild(renderer.domElement); // 载入到dom
  controls.value = new OrbitControls(camera, renderer.domElement);

  //initguandao();
  //initDian();
  initGround();
  initGrid();
  controls.value.addEventListener("change", (e) => {
    // console.log(e);
    // console.log("camera.position", camera.position);
    renderer.render(scene, camera);
  });
};

function initLine(pArr) {
  var points = [];
  var geometry = new THREE.BufferGeometry();
  const pointsArray = [];
  for (var i = 0; i < pArr.length; i++) {
    var randomX = pArr[i].x;
    var randomY = pArr[i].y;
    var randomZ = pArr[i].z;
    var vector = new THREE.Vector3(randomX, randomY, randomZ);

    pointsArray.push(vector);
    points.push(vector);
  }
  geometry.setFromPoints(pointsArray);
  var material = new THREE.LineBasicMaterial({
    color: 0x0000ff,
  });
  var line = new THREE.Line(geometry, material);
  scene.add(line);
  return points;
}

function initGround() {
  var geometry = new THREE.BufferGeometry();

  const pointsArray = [new THREE.Vector3(start, 0, 0), new THREE.Vector3(end, 0, 0)];

  geometry.setFromPoints(pointsArray);

  for (var i = 0; i <= length / ws; i++) {
    var heng = new THREE.Line(
      geometry,
      new THREE.LineBasicMaterial({ color: new Color("#888"), opacity: 0.1 })
    );
    heng.position.z = start + i * ws;
    scene.add(heng);
    var shu = new THREE.Line(
      geometry,
      new THREE.LineBasicMaterial({ color: new Color("#888"), opacity: 1 })
    );
    shu.position.x = start + i * ws;
    shu.rotation.y = (90 * Math.PI) / 180;

    scene.add(shu);
  }
}
var mesh = [];
var graph: any = [];
function initGrid() {
  for (var i = 0; i < length / ws; i++) {
    var nodeRow = [];
    for (var j = 0; j < length / ws; j++) {
      var salt = Math.random() * 7;
      if (salt > 2) {
        nodeRow.push(1);
      } else {
        nodeRow.push(0);
      }
      if (salt <= 2) {
        var cube = new THREE.Mesh(
          new THREE.SphereGeometry(ws / 2, ws / 2, ws / 2),
          new THREE.MeshBasicMaterial({
            color: 0xc0c0c0,
          })
        );
        let x = start + (ws * j + ws / 2);
        let z = start + ws * i + ws / 2;
        cube.position.set(x, 1, z);
        cube.name = "qiu";
        scene.add(cube);
        mesh.push(cube);
      }
    }
    graph.push(nodeRow);
  }
}
var resultArray = new Array();
function caculatePath(resultArray: any) {
  var maps = new astar.Graph(graph); // 地图
  var startX = parseInt(resultArray[0].position.z / ws);
  var startY = parseInt(resultArray[0].position.x / ws);
  var endX = parseInt(resultArray[1].position.z / ws);
  var endY = parseInt(resultArray[1].position.x / ws);
  var start = maps.grid[startX][startY];
  var end = maps.grid[endX][endY];
  var result = astar.search(maps, start, end);
  if (result.length == 0) {
    alert("无可到达路径");

    return;
  }

  var nArr = [
    {
      x: resultArray[0].position.x,
      z: resultArray[0].position.z,
      y: 1.2,
    },
  ];
  for (var i = 0; i < result.length; i++) {
    let d = {
      x: result[i].y * ws + ws / 2,
      y: 1.2,
      z: result[i].x * ws + ws / 2,
    };
    nArr.push(d);
  }
  initLine(nArr);
}

var isCaculate = ref(false);
function initSphere(x, z) {
  if (isCaculate.value) {
    cleanSphere();
  }
  var geometry = new THREE.SphereGeometry(ws / 2, 30, 30); //球体几何
  var material = new THREE.MeshBasicMaterial({
    color: 0xffff00,
  }); //网格基础材料

  if (resultArray.length == 0) {
    var sphere = new THREE.Mesh(geometry, material);
    sphere.position.x = x;
    sphere.position.y = 1;
    sphere.position.z = z;
    resultArray.push(sphere);
    scene.add(sphere);
  } else if (resultArray[0].position.x != x || resultArray[0].position.z != z) {
    var sphere = new THREE.Mesh(geometry, material);
    sphere.position.x = x;
    sphere.position.y = 1;
    sphere.position.z = z;
    resultArray.push(sphere);
    scene.add(sphere);
    caculatePath(resultArray);
    isCaculate.value = true;
    resultArray = new Array();
  }
}
// 清除小球
function cleanSphere() {
  let child = scene.children; //获取场景中的所有子对象
  for (var i = 0; i < child.length; i++) {
    if (child[i].geometry instanceof THREE.SphereGeometry) {
      //几何对象是球体几何
      scene.remove(child[i]); //从场景中移除
      i--;
    }
  }
  isCaculate.value = false;
}

function initGrids() {
  for (var i = 0; i < length / ws; i++) {
    var nodeRow = [];
    for (var j = 0; j < length / ws; j++) {
      var salt = Math.random() * 7;
      if (salt > 2) {
        nodeRow.push(1);
      } else {
        nodeRow.push(0);
      }
      if (salt <= 2) {
        var cube = new THREE.Mesh(
          new THREE.SphereGeometry(ws / 2, ws / 2, ws / 2),
          new THREE.MeshBasicMaterial({
            color: 0xc0c0c0,
          })
        );
        let x = ws * j + ws / 2;
        let z = ws * i + ws / 2;
        cube.position.set(x, ws, z);

        scene.add(cube);
        mesh.push(cube);
      }
    }
    graph.push(nodeRow);
  }
}

const initguandao = () => {
  const p1 = new Vector3(0, 0, 100);
  const p2 = new Vector3(0, 0, 30);
  const p3 = new Vector3(0, 0, 0);
  const p4 = new Vector3(30, 0, 0);
  const p5 = new Vector3(100, 0, 0);

  // 1. 3D直线线段
  const line1 = new LineCurve3(p1, p2);
  // 2. 三维二次贝塞尔曲线
  const curve = new QuadraticBezierCurve3(p2, p3, p4);
  // 3. 3D直线线段
  const line2 = new LineCurve3(p4, p5);
  const CurvePaths = new CurvePath();
  // 三条线拼接为一条曲线
  CurvePaths.curves.push(line1, curve, line2);

  const texLoader = new TextureLoader();
  //纹理贴图
  const texture = texLoader.load(
    "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4415327a-1d82-4985-8302-44b07a8498c0%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1687512010&t=df81831ff29236e2796899fdcaf43b74"
  );
  console.log(texture);
  const material = new MeshLambertMaterial({
    map: texture,
    side: DoubleSide, //双面显示看到管道内壁
  });
  // CurvePath:路径   40：沿着轨迹细分数  2：管道半径   25：管道截面圆细分数
  const geometry = new TubeGeometry(CurvePaths, 50, 5, 25);
  let planes = new Mesh(geometry, material); // 设置地面的位置
  planes.position.y = 11;
  scene.add(planes);
};

const initDian = () => {
  const path = new CatmullRomCurve3([
    new Vector3(-50, 20, 90),
    new Vector3(-10, 40, 40),
    new Vector3(0, 0, 0),
    new Vector3(60, -60, 0),
    new Vector3(70, 0, 80),
  ]);
  const geometry = new TubeGeometry(path, 200, 5, 30);
  const texLoader = new TextureLoader();
  //纹理贴图
  const texture = texLoader.load(
    "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4415327a-1d82-4985-8302-44b07a8498c0%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1687512010&t=df81831ff29236e2796899fdcaf43b74"
  );
  //UV坐标U方向阵列模式
  texture.wrapS = RepeatWrapping;
  //纹理沿着管道方向阵列(UV坐标U方向)
  texture.repeat.x = 10;
  const material = new MeshLambertMaterial({
    map: texture,
    side: DoubleSide, //双面显示看到管道内壁
  });
  const mesh = new Mesh(geometry, material);
  const pointsArr = path.getSpacedPoints(2000);
  scene.add(mesh);
  renderer.render(scene, camera);
};

const addPlane = () => {
  let planeGeometry = new PlaneGeometry(1000, 1000); //地面的材质，宽高

  const texLoader = new THREE.TextureLoader();
  // .load()方法加载图像，返回一个纹理对象Texture
  const texture = texLoader.load(tietu);
  const material = new THREE.MeshLambertMaterial({
    // 设置纹理贴图：Texture对象作为材质map属性的属性值
    map: texture, //map表示材质的颜色贴图属性
  });

  let planeMaterial = new MeshBasicMaterial({ color: new Color("#efefef") });
  let plane = new Mesh(planeGeometry, planeMaterial); // 设置地面的位置
  plane.name = "plane";
  plane.rotation.x = -0.5 * Math.PI; // 倾斜把竖着的垂直下来，具体参考圆周率
  plane.position.y = -10;
  scene.add(plane); //将地面添加到坐标轴中
};
addPlane();
function animate() {
  requestAnimationFrame(animate);
  // zhuanquan();
  renderer.render(scene, camera);
}

const R = 500; //相机圆周运动的半径
let angle = 0;
const zhuanquan = () => {
  angle += 0.001;
  camera.position.x = R * Math.cos(angle);
  camera.position.z = R * Math.sin(angle);
  camera.position.y = 100;
};

const onClick = (event) => {
  const raycaster = new THREE.Raycaster();
  const mouse = new THREE.Vector2();
  // 计算鼠标或触摸点的位置
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / height) * 2 + 1;
  // 更新射线   注意——> this.camera 是相机   定义到data里的
  raycaster.setFromCamera(mouse, camera);
  // 计算与所有对象的交点
  const intersects = raycaster.intersectObjects(scene.children, true);
  console.log("交点");
  console.log(intersects);

  if (intersects.length > 0) {
    // 处理点击事件
    // intersects[0] 包含了第一个交点
    const clickedObject = intersects[0].object;
    //通过点击到该模型用名字匹配
    if (clickedObject.name === clickedObject.name) {
      console.log("获取的当前模型信息:", clickedObject);
      if (clickedObject.name != "plane") {
        clickedObject.material = new THREE.MeshBasicMaterial({
          color: "#FF00FF",
          transparent: true,
          opacity: 0.5,
        });

        // controls.value?.target.set(clickedObject.position);
        renderer.render(scene, camera);
      }
    }
  }
};

function pickupObjects(event) {
  // 点击屏幕创建一个向量
  var raycaster = new THREE.Raycaster();
  var vector = new THREE.Vector2(
    (event.clientX / window.innerWidth) * 2 - 1,
    -(event.clientY / window.innerHeight) * 2 + 1
  );
  var fxl = new THREE.Vector3(0, 1, 0);
  var groundplane = new THREE.Plane(fxl, 0);
  raycaster.setFromCamera(vector, camera);
  var ray = raycaster.ray;
  let intersects = ray.intersectPlane(groundplane);
  let x = intersects.x;
  let z = intersects.z;

  if (x < 0 || z < 0 || length < z || length < x) {
    return;
  }

  var k, m;
  for (var i = 0; i < length; i += ws) {
    if (x >= i && x < i + ws) {
      k = i + ws / 2;
    }
  }
  for (var j = 0; j < length; j += ws) {
    if (z >= j && z < j + ws) {
      m = j + ws / 2;
    }
  }

  initSphere(k, m); //初始化球体
}
document.addEventListener("click", pickupObjects, false);
</script>

<style lang="scss" scoped>
.container {
  width: 100%;
  height: 600px;
}
.three {
}
</style>
